package com.qingyun.material.service.impl;

import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qingyun.common.dto.Result;
import com.qingyun.common.util.RedisConstants;
import com.qingyun.common.util.UserHolder;
import com.qingyun.material.dto.MaterialDTO;
import com.qingyun.material.entity.Material;
import com.qingyun.material.entity.MaterialTask;
import com.qingyun.material.mapper.MaterialMapper;
import com.qingyun.material.service.IMaterialService;
import com.qingyun.material.utils.FileUploadUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.redis.connection.stream.MapRecord;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;

import static com.qingyun.common.util.RedisConstants.LOGIN_USER_KEY;


/**
 * <p>
 * 资料中心 服务实现类
 * </p>
 *
 * @author your_name
 * @since 2025-08-23
 */
@Service
@Slf4j
public class MaterialServiceImpl extends ServiceImpl<MaterialMapper, Material> implements IMaterialService {

    @Autowired
    private MaterialMapper materialMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private FileUploadUtil fileUploadUtil;
    @Autowired
    private UserHolder userHolder;
    @Override
    public Result uploadMaterial(MaterialDTO materialDTO, String token) {
        Long userId = userHolder.getUserId();
        if (userId == null) {
            return Result.fail("用户未登录或Token失效");
        }

        // 2. 处理上传的文件
        MultipartFile file = materialDTO.getFile();
        if (file == null || file.isEmpty()) {
            return Result.fail("上传文件不能为空");
        }
        // 2.1 先同步落地文件，得到相对路径与元数据
        String relativeFilePath;
        try {
            relativeFilePath = fileUploadUtil.uploadFile(file);
        } catch (IOException e) {
            return Result.fail("文件保存失败: " + e.getMessage());
        }

        // 2.2 构造任务并入队（不传 MultipartFile，只传路径与元信息）
        MaterialTask materialTask = new MaterialTask();
        materialTask.setUserId(userId);
        materialTask.setTitle(materialDTO.getTitle());
        materialTask.setDescription(materialDTO.getDescription());
        materialTask.setCategory(materialDTO.getCategory());
        materialTask.setGrade(materialDTO.getGrade());
        materialTask.setSubject(materialDTO.getSubject());
        materialTask.setOriginalFileName(file.getOriginalFilename());
        materialTask.setFilePath(relativeFilePath);
        materialTask.setFileSize(file.getSize());
        materialTask.setMimeType(file.getContentType());

        if (stringRedisTemplate != null) {
            String taskJson = JSONUtil.toJsonStr(materialTask);
            MapRecord<String, String, String> record = MapRecord.create(
                    RedisConstants.MATERIAL_TASK_QUEUE,
                    java.util.Map.of(RedisConstants.FIELD_TASK_JSON, taskJson)
            );
            stringRedisTemplate.opsForStream().add(record);
        }
        // 返回异步受理
        return Result.ok("任务已提交");
    }

    public void saveMaterial(MaterialDTO materialDTO,Long userId){
        if (userId == null) {
            throw new RuntimeException("未存储当前用户ID");
        }
        if (materialDTO == null) {
            throw new RuntimeException("任务内容为空");
        }

        // 由入队时填好的元信息完成入库，不再读取 MultipartFile
        Material material = new Material();
        material.setTitle(materialDTO.getTitle());
        material.setDescription(materialDTO.getDescription());
        material.setCategory(materialDTO.getCategory());
        material.setGrade(materialDTO.getGrade());
        material.setSubject(materialDTO.getSubject());
        material.setOriginalFileName(materialDTO.getOriginalFileName());
        material.setFilePath(materialDTO.getFilePath());
        material.setFileSize(materialDTO.getFileSize());
        material.setMimeType(materialDTO.getMimeType());

        material.setUploaderId(userId);
        material.setStatus(1);
        material.setDownloadCount(0);
        materialMapper.insert(material);
    }

    @Override
    public Result downloadMaterial(Long id, String token, HttpServletResponse response) {
        try {
            // 1. 验证用户登录状态
            Long userId = userHolder.getUserId();
            if (userId == null) {
                return Result.fail("用户未登录或Token失效");
            }

            // 2. 查询资料信息
            Material material = materialMapper.selectById(id);
            if (material == null) {
                throw new RuntimeException("资料不存在");
            }
            
            if (material.getStatus() == 0) {
                throw new RuntimeException("资料已被下架");
            }

            // 3. 构建文件路径
            String fullFilePath = fileUploadUtil.getFullPath(material.getFilePath());
            File file = new File(fullFilePath);
            
            if (!file.exists()) {
                throw new RuntimeException("文件不存在");
            }

            // 4. 设置响应头
            response.setContentType(material.getMimeType());
            response.setContentLengthLong(material.getFileSize());
            
            // 设置文件名编码，支持中文
            String fileName = material.getOriginalFileName();
            if (StrUtil.isNotBlank(fileName)) {
                String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString());
                response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedFileName + "\"");
            }

            // 5. 写入文件流
            try (FileInputStream fis = new FileInputStream(file);
                 OutputStream os = response.getOutputStream()) {
                
                byte[] buffer = new byte[1024];
                int bytesRead;
                while ((bytesRead = fis.read(buffer)) != -1) {
                    os.write(buffer, 0, bytesRead);
                }
                os.flush();
            }

            // 6. 更新下载次数
            LambdaUpdateWrapper<Material> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(Material::getId, id)
                        .setSql("download_count = download_count + 1");
            materialMapper.update(null, updateWrapper);
        } catch (Exception e) {
            throw new RuntimeException("下载失败：" + e.getMessage());
        }
        return Result.ok();
    }

    @Override
    public Result getMaterialList(String category, String grade, String keyword, String token, String subject) {
        try {
            log.info("调用获取信息接口");
            // 1. 验证用户登录状态
            Long userId = userHolder.getUserId();
            if (userId == null) {
                return Result.fail("用户信息获取失败");
            }

            // 3. 构建查询条件
            LambdaQueryWrapper<Material> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Material::getUploaderId, userId) // 只查询当前用户的资料
                        .eq(Material::getStatus, 1); // 只查询有效资料

            // 添加筛选条件
            if (StrUtil.isNotBlank(category)) {
                queryWrapper.eq(Material::getCategory, category);
            }
            if (StrUtil.isNotBlank(grade)) {
                queryWrapper.eq(Material::getGrade, grade);
            }
            if (StrUtil.isNotBlank(keyword)) {
                queryWrapper.like(Material::getTitle, keyword);
            }
            if (StrUtil.isNotBlank(subject)) {
                queryWrapper.eq(Material::getSubject, subject);
            }

            // 按创建时间倒序排列
            queryWrapper.orderByDesc(Material::getCreateTime);

            // 4. 执行查询
            List<Material> materials = materialMapper.selectList(queryWrapper);

            return Result.ok(materials);

        } catch (Exception e) {
            return Result.fail("查询失败：" + e.getMessage());
        }
    }

    @Override
    public Result getDownloadableMaterials(String category, String grade, String keyword, String token, String subject) {
        try {
            log.info("调用获取可下载资料接口");
            Long userId = userHolder.getUserId();
            if (userId == null) {
                return Result.fail("用户未登录或Token失效");
            }

            // 2. 构建查询条件 - 查询所有有效的资料，不限制上传者
            LambdaQueryWrapper<Material> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Material::getStatus, 1); // 只查询有效资料
            
            // 添加筛选条件
            if (StrUtil.isNotBlank(category)) {
                queryWrapper.eq(Material::getCategory, category);
            }
            if (StrUtil.isNotBlank(grade)) {
                queryWrapper.eq(Material::getGrade, grade);
            }
            if (StrUtil.isNotBlank(keyword)) {
                queryWrapper.like(Material::getTitle, keyword);
            }
            if (StrUtil.isNotBlank(subject)) {
                queryWrapper.eq(Material::getSubject, subject);
            }
            
            // 按创建时间倒序排列
            queryWrapper.orderByDesc(Material::getCreateTime);

            // 3. 执行查询
            List<Material> materials = materialMapper.selectList(queryWrapper);

            if(materials.isEmpty()){
                return Result.fail("暂无满足条件资料");
            }

            return Result.ok(materials);

        } catch (Exception e) {
            return Result.fail("查询失败：" + e.getMessage());
        }
    }

    @Override
    public Result deleteMaterial(Long id, String token) {
        try {
            // 1. 验证用户登录状态
            String userInfoKey = LOGIN_USER_KEY + token;
            Boolean hasKey = stringRedisTemplate.hasKey(userInfoKey);
            if (BooleanUtil.isFalse(hasKey)) {
                return Result.fail("用户未登录或登录已过期");
            }

            // 2. 获取用户信息
            Long userId = userHolder.getUserId();
            if (userId == null) {
                return Result.fail("用户未登录或Token失效");
            }


            // 3. 查询资料信息
            Material material = materialMapper.selectById(id);
            if (material == null) {
                return Result.fail("资料不存在");
            }
            
            // 4. 验证权限（只能删除自己的资料）
            if (!material.getUploaderId().equals(userId)) {
                return Result.fail("无权限删除此资料");
            }

            // 5. 软删除（更新状态为0）
            LambdaUpdateWrapper<Material> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(Material::getId, id)
                        .set(Material::getStatus, 0);
            
            int result = materialMapper.update(null, updateWrapper);
            if (result > 0) {
                return Result.ok("删除成功");
            } else {
                return Result.fail("删除失败");
            }

        } catch (Exception e) {
            return Result.fail("删除失败：" + e.getMessage());
        }
    }
}
